package com.intelligentclass.controller;

import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.intelligentclass.constant.UserType;
import com.intelligentclass.entity.*;
import com.intelligentclass.exception.UserTypeException;
import com.intelligentclass.mydata.MyJson;
import com.intelligentclass.requestItem.HomeworkItem;
import com.intelligentclass.requestItem.TeacherHomeworkItem;
import com.intelligentclass.services.*;
import com.intelligentclass.utils.JWTUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@RestController
@CrossOrigin(origins = "*")
public class HomeworkController {

    private final HomeworkService homeworkService;
    private final TeachingService teachingService;
    private final CommitService commitService;
    private final JudgeService judgeService;
    private final HomeworkIntroduceService homeworkIntroduceService;

    private static final String CREATEHOMEWORK_PATH = "D:\\IntelligentClass\\HomeworkContent\\";

    @Autowired
    public HomeworkController(HomeworkService homeworkService, TeachingService teachingService, CommitService commitService,
                              JudgeService judgeService, HomeworkIntroduceService homeworkIntroduceService) {
        this.homeworkService = homeworkService;
        this.teachingService = teachingService;
        this.commitService = commitService;
        this.judgeService = judgeService;
        this.homeworkIntroduceService = homeworkIntroduceService;
    }

    @GetMapping("/test/homework")
    public String testHomework() {
        Commit commit = commitService.getCommit(1);
        System.out.println(commit.getDir());
        return commit.getDir();
    }

    /**
     *
     * @param header
     *      header must contain a valid token used to identify if the user is correct
     * @param cid
     *      Class id. To get teaching information from database
     * @return
     */
    @PostMapping("/api/homework/search")
    public ResponseEntity<?> searchHomework(@RequestHeader Map<String, String> header, @RequestParam("cid") int cid){

        MyJson json = new MyJson();
        String token = header.get("token");
        DecodedJWT jwt;
        try {
            //identify if the token is valid
            jwt = JWTUtil.verifyToken(token);
        }
        catch (TokenExpiredException e) {
            json.setMessage("Token is expired");
            json.setStatus(400);
            json.addData("status", 0);
            return ResponseEntity.ok().body(json);
        }
        catch (Exception e) {
            System.exit(1);
            return null;
        }

        int userType = jwt.getClaim("usertype").asInt();
        String sno = jwt.getClaim("username").asString();
//        int userType = UserType.STUDNET;
//        String sno  = "22301102";

        if(userType != UserType.TEACHER && userType != UserType.STUDENT){
            json.setMessage("Invalid user type");
            json.setStatus(400);
            json.addData("status", 0);
            return ResponseEntity.ok().body(json);
        }

        //get the total number of students of this class
        Teaching t = teachingService.searchTeaching(cid);
        List<Homework> homeworks = t.getHomeworkList();

        List<Student> students = t.getStudentList();
        int totalNumber = students.size();

        System.out.println("before create list");

        //get ALL homeworks of this class;
        if(userType == UserType.STUDENT) {
            List<HomeworkItem> homeworkItems = new ArrayList<>();
            for (Homework h : homeworks) {

                if (h.getIsPublish() == 0) continue;

                HomeworkItem homeworkItem = new HomeworkItem(h.getHid(), h.getCid(), h.getHname(), h.getBegindate(), h.getEnddate(), h.getFullGrade());
                homeworkItem.setTotalNumber(totalNumber);
                List<Commit> commits = h.getCommits();
                boolean flag = false;
                for (Commit c : commits) {
                    String s = c.getSno();
                    if (c.getSno().equals(sno)) {
                        flag = true;
                        break;
                    }
                }
                if (flag) {
                    homeworkItem.setIsCommit(1);
                }
                //calculate the number of submits
                homeworkItem.setSubNumber(commits.size());
                homeworkItems.add(homeworkItem);
            }


            System.out.println("after create list");

            //return result
            json.setMessage("Successfully search homework");
            json.setStatus(200);
            json.addData("homeworks", homeworkItems);
            token = JWTUtil.updateToken(token);
            json.addData("token", token);

            System.out.println("before toString");
            System.out.println(json.toString());
            System.out.println("after toString");

            return ResponseEntity.ok(json);
        }
        else{
            List<TeacherHomeworkItem> list = new ArrayList<>();
            for(Homework h : homeworks){
                TeacherHomeworkItem item = new TeacherHomeworkItem(h.getHid(), h.getCid(), h.getHname(), h.getBegindate(), h.getEnddate(), h.getIsPublish(), h.getFullGrade());
                item.setTotalNumber(totalNumber);
                List<Commit> commits = h.getCommits();
                item.setSubNumber(commits.size());
                list.add(item);
            }
            json.setMessage("Successfully search homework");
            json.setStatus(200);
            json.addData("homeworks", list);
            token = JWTUtil.updateToken(token);
            json.addData("token", token);
            System.out.println("before toString");
            System.out.println(json.toString());
            System.out.println("after toString");
            return ResponseEntity.ok(json);
        }
    }

    /**
     *
     * @param header
     *      header must contain a valid token used to identify if the user is correct
     * @param file
     *      the submitted file
     * @param jsonData
     *      contain cid, sno and hid.
     * @return
     */
    @PostMapping("/api/homework/save")
    public ResponseEntity<?> uploadFile(
            @RequestHeader Map<String, String> header,
            @RequestParam("file") MultipartFile file,
            @RequestParam("jsonData") String jsonData) {

        String token = header.get("token");
        DecodedJWT jwt;
        try{
            jwt = JWTUtil.verifyToken(token);
            int userType = jwt.getClaim("usertype").asInt();
            if(userType != UserType.STUDENT){
                throw new UserTypeException();
            }
        }
        catch(UserTypeException e){
            MyJson json = new MyJson();
            json.setMessage("Not enough access permissions");
            json.setStatus(401);
            json.addData("status", -1);
            return ResponseEntity.badRequest().body(json.toString());
        }
        catch(TokenExpiredException e){
            MyJson json = new MyJson();
            json.setMessage("Token has expired");
            json.setStatus(402);
            json.addData("status", -2);
        }
        catch(Exception e){
            System.exit(1);
        }

        //analysis the data from json
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            JsonData parsedJson = objectMapper.readValue(jsonData, JsonData.class);
            MyJson json = new MyJson();

            int cid = parsedJson.getCid();
            String sno = parsedJson.getSno();
            int hid = parsedJson.getHid();

            Teaching t = teachingService.searchTeaching(cid);
            List<Student> students = teachingService.getAllStudents(cid);
            List<Homework> homeworks = t.getHomeworkList();

            if(students == null) {
                json.setStatus(200);
                json.setMessage("Wrong cid or sno or hid");
                return ResponseEntity.ok(json.toString());
            }
            boolean flag = false;
            for(Student student : students) {
                if(student.getSno().equals(sno)) {
                    flag = true;
                    break;
                }
            }
            for(Homework homework : homeworks) {
                if(homework.getHid() == hid) {
                    flag = true;
                    break;
                }
            }
            if(!flag) {
                json.setStatus(200);
                json.setMessage("Wrong cid or sno or hid");
                return ResponseEntity.ok(json.toString());
            }
            String fileName = file.getOriginalFilename();

//            String path = homeworkService.saveHomework(file, sno, cid);
            String path = commitService.commitHomework(sno, hid, cid, file);
            String message = "File uploaded successfully with CID: " + cid + " and SNO: " + sno;
            message += "\nPath: " + path;
            json.setStatus(200);
            json.setMessage(message);
            json.addData("cid", cid);
            json.addData("sno", sno);
            json.addData("Path", path);
            return ResponseEntity.ok().body(json);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }

    /**
     *
     * @param header must contain a valid token to identify user
     * @param data contain cid, name, beginDate, endDate and content
     * @return
     */
    @PostMapping("/api/homework/createHomework")
    public ResponseEntity<?> createHomework(@RequestHeader Map<String, String> header,
                                            @RequestBody CreateHomeworkData data,
                                            @RequestParam(value = "file", required = false) MultipartFile file){
        MyJson json = new MyJson();
        String token = header.get("token");
        DecodedJWT jwt;
        int usertype;
        try{
            jwt = JWTUtil.verifyToken(token);
            usertype = jwt.getClaim("usertype").asInt();
            if(usertype != UserType.TEACHER) {
                json.setMessage("Insufficient permissions");
                json.setStatus(401);
                json.addData("status", -1);
                return ResponseEntity.badRequest().body(json);
            }
        }
        catch(TokenExpiredException e){
            json.setMessage("Token has expired");
            json.setStatus(402);
            json.addData("status", -2);
            return ResponseEntity.badRequest().body(json);
        }
        catch(Exception e){
            json.setMessage("Unexpected error");
            json.setStatus(500);
            json.addData("status", -1);
            return ResponseEntity.badRequest().body(json);
        }

        int cid = data.getCid();
        String hname = data.getHname();
        String beginDate = data.getBeginDate();
        String endDate = data.getEndDate();
        String content = data.getContent();
        int fullGrade = data.getFullGrade();

        Homework check = homeworkService.getHomework(hname, cid);
        if(check != null){
            json.setMessage("Homework already exists");
            json.setStatus(403);
            json.addData("status", -1);
            return ResponseEntity.badRequest().body(json);
        }

        LocalDateTime bdate;
        LocalDateTime edate;
        try{
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            bdate = LocalDateTime.parse(beginDate, formatter);
            edate = LocalDateTime.parse(endDate, formatter);
        }
        catch(Exception e){
            json.setMessage("Wrong formatted date");
            json.setStatus(403);
            json.addData("status", -2);
            return ResponseEntity.badRequest().body(json);
        }

        Homework homework = new Homework(hname, cid, bdate, edate);
        homework.setContent(content);
        homework.setFullGrade(fullGrade);
        homework = homeworkService.save(homework);

        homeworkIntroduceService.createNewIntroduce(homework.getHid(), data.getIntroduction());

        json.setMessage("Homework created successfully");
        json.setStatus(200);
        json.addData("status", 1);
        return ResponseEntity.ok().body(json);
    }

    @GetMapping("/api/homework/publishHomework")
    public ResponseEntity<?> publishHomework(@RequestHeader Map<String, String> header,
                                             @RequestParam("hid") int hid,
                                             @RequestParam("isPublish") int isPublish){
        MyJson json = new MyJson();
        String token = header.get("token");
        DecodedJWT jwt;
        int usertype;
        try{
            jwt = JWTUtil.verifyToken(token);
            usertype = jwt.getClaim("usertype").asInt();
            if(usertype != UserType.TEACHER) {
                json.setMessage("Insufficient permissions");
                json.setStatus(403);
                json.addData("status", -1);
                return ResponseEntity.badRequest().body(json);
            }
        }
        catch(TokenExpiredException e){
            json.setMessage("Token has expired");
            json.setStatus(403);
            json.addData("status", -2);
            return ResponseEntity.badRequest().body(json);
        }
        catch(Exception e){
            json.setMessage("Unexpected error");
            json.setStatus(500);
            json.addData("status", -1);
            return ResponseEntity.badRequest().body(json);
        }

        Homework homework = homeworkService.getHomework(hid);
        if(homework == null){
            json.setMessage("Homework not found");
            json.setStatus(404);
            json.addData("status", -1);
            return ResponseEntity.badRequest().body(json);
        }
        homework.setIsPublish(isPublish);
        homework = homeworkService.save(homework);

        json.setMessage("Homework published successfully");
        json.setStatus(200);
        json.addData("status", 1);
        return ResponseEntity.ok().body(json);
    }

    @PostMapping("/api/homework/getSubmitList")
    public ResponseEntity<?> getSubmitList(@RequestHeader Map<String, String> header,
                                           @RequestParam("hid") int hid){
        MyJson json = new MyJson();
        String token = header.get("token");
        DecodedJWT jwt;
        int usertype;
        try{
            jwt = JWTUtil.verifyToken(token);
            usertype = jwt.getClaim("usertype").asInt();
            if(usertype != UserType.TEACHER) {
                json.setMessage("Insufficient permissions");
                json.setStatus(403);
                json.addData("status", -1);
                return ResponseEntity.badRequest().body(json);
            }
        }
        catch(TokenExpiredException e){
            json.setMessage("Token has expired");
            json.setStatus(403);
            json.addData("status", -2);
            return ResponseEntity.badRequest().body(json);
        }
        catch(Exception e){
            json.setMessage("Unexpected error");
            json.setStatus(500);
            json.addData("status", -1);
            return ResponseEntity.badRequest().body(json);
        }

        List<Commit> commits = commitService.findAll(hid);
        List<CommitData> result = new ArrayList<>();
        for(Commit commit : commits){
            String dir = commit.getDir();
            String[] s = dir.split("\\\\");
            String commitName = s[s.length - 1];

            result.add(new CommitData(commit.getCommitid(), commitName, commit.getSno()));
        }
        json.setStatus(200);
        json.setMessage("Successfully get All submits");
        json.addData("status", 1);
        json.addData("submits", result);
        return ResponseEntity.ok().body(json);
    }

    @GetMapping("/api/homework/judgeHomework")
    public ResponseEntity<?> judgeHomework(@RequestHeader Map<String, String> header,
                                           @RequestParam("commitid") int commitid,
                                           @RequestParam("grade") int grade){
        MyJson json = new MyJson();
        String token = header.get("token");
        DecodedJWT jwt;
        int usertype;
        try{
            jwt = JWTUtil.verifyToken(token);
            usertype = jwt.getClaim("usertype").asInt();
            if(usertype != UserType.TEACHER) {
                json.setMessage("Insufficient permissions");
                json.setStatus(403);
                json.addData("status", -1);
                return ResponseEntity.badRequest().body(json);
            }
        }
        catch(TokenExpiredException e){
            json.setMessage("Token has expired");
            json.setStatus(403);
            json.addData("status", -2);
            return ResponseEntity.badRequest().body(json);
        }
        catch(Exception e){
            json.setMessage("Unexpected error");
            json.setStatus(500);
            json.addData("status", -1);
            return ResponseEntity.badRequest().body(json);
        }

        Judge judge = new Judge();
        judge.setCommitid(commitid);
        judge.setGrade(grade);
        judgeService.save(judge);

        json.setMessage("Successfully judge the homework");
        json.setStatus(200);
        return ResponseEntity.ok().body(json);
    }

    @PostMapping("/api/homework/getHomeworkIntroduction")
    public ResponseEntity<?> getHomeworkIntroduction(@RequestHeader Map<String, String> header, @RequestParam("hid") int hid){
        MyJson json = new MyJson();
        String token = header.get("token");
        DecodedJWT jwt;
        int usertype;
        try{
            jwt = JWTUtil.verifyToken(token);
            usertype = jwt.getClaim("usertype").asInt();
            if(usertype != UserType.TEACHER && usertype != UserType.STUDENT) {
                json.setMessage("Insufficient permissions");
                json.setStatus(403);
                json.addData("status", -1);
                return ResponseEntity.badRequest().body(json);
            }
        }
        catch(TokenExpiredException e){
            json.setMessage("Token has expired");
            json.setStatus(403);
            json.addData("status", -2);
            return ResponseEntity.badRequest().body(json);
        }
        catch(Exception e){
            json.setMessage("Unexpected error");
            json.setStatus(500);
            json.addData("status", -1);
            return ResponseEntity.badRequest().body(json);
        }

        json.setStatus(200);
        json.setMessage("Successfully get Homework introduction");
        json.addData("Introduction", homeworkIntroduceService.getIntroduction(hid));
        return ResponseEntity.ok().body(json);
    }


    /**
     * this class is used to receive the info of submission.
     */
    static class JsonData {
        private int cid;
        private String sno;
        private int hid;

        // Getters and Setters
        public int getCid() { return cid; }
        public void setCid(int cid) { this.cid = cid; }

        public String getSno() { return sno; }
        public void setSno(String sno) { this.sno = sno; }

        public int getHid() { return hid;}
        public void setHid(int hid) { this.hid = hid; }
    }

    public static class CreateHomeworkData{
        private int cid;
        private String hname;
        private String beginDate;
        private String endDate;
        private String content;
        private int fullGrade;
        private String introduction;

        public CreateHomeworkData(){}
        public CreateHomeworkData(int cid, String hname, String beginDate, String endDate, String content, int fullGrade) {
            this(cid, hname, beginDate, endDate, content);
            this.fullGrade = fullGrade;
        }
        public CreateHomeworkData(int cid, String hname, String beginDate, String endDate, String content) {
            this(cid, hname, beginDate, endDate);
            this.content = content;
        }
        public CreateHomeworkData(int cid, String hname, String beginDate, String endDate){
            this.cid = cid;
            this.hname = hname;
            this.beginDate = beginDate;
            this.endDate = endDate;
            content = "";
            fullGrade = 100;
        }
        public CreateHomeworkData(int cid, String hname, String beginDate, String endDate, String content, int fullGrade, String introduction){
            this( cid, hname, beginDate, endDate, content, fullGrade);
            this.introduction = introduction;
        }

        public int getCid() {
            return cid;
        }
        public String getBeginDate() {
            return beginDate;
        }
        public String getEndDate() {
            return endDate;
        }
        public String getHname() {
            return hname;
        }
        public String getContent() {
            return content;
        }

        public int getFullGrade() {
            return fullGrade;
        }
        public String getIntroduction() {
            return introduction;
        }
    }

    public static class CommitData{
        private int commitid;
        private String name;
        private String sno;

        public CommitData(int commitid, String name, String sno) {
            this.commitid = commitid;
            this.name = name;
            this.sno = sno;
        }

        public int getCommitid() {
            return commitid;
        }
        public String getName() {
            return name;
        }
        public String getSno() {
            return sno;
        }
    }

}
